/*
 * pml_bom.c
 *
 *  Created on: 2013年8月25日
 *      Author: lius
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pml_bom.h"

#define printcolor(fmt,arg...) \
{ \
	printf("\033[32m"); \
	printf(fmt, ##arg);  \
	printf("\033[0m"); \
}

static inline int get_oracle_S(factor_m *pm, unsigned char state)
{
	if(!state)
		return NULL_STATE;
	else
		return pm->p_supply_state[state];
}

static inline void set_oracle_S(factor_m *pm, unsigned char state, unsigned char supply_state)
{
	pm->p_supply_state[state] = supply_state;
}

static void oracle_add_letter(factor_m *pm, unsigned char c)
{
	pm->p_state[pm->cur_state].shift[c] = pm->match_state;
	int k = get_oracle_S(pm, pm->cur_state);
	int s;
	while(k != NULL_STATE && pm->p_state[k].shift[c] == 0)
	{
		pm->p_state[k].shift[c] = pm->match_state;
		k = get_oracle_S(pm, k);
	}

	if(k == NULL_STATE)
		s = 0;
	else
		s = pm->p_state[k].shift[c];

	set_oracle_S(pm, pm->match_state, s);

	pm->match_state ++;
	pm->cur_state = pm->match_state - 1;
}

static inline void print_oracle_state_m(factor_m *pm)
{
#ifdef ILLUSTRATE
	int i = 0;
	const int len = 256;
	int j;
	for(; i < pm->pattern_len + 1; i ++)
	{
		for(j = 0; j < len; j ++)
		{
			int state = pm->p_state[i].shift[j];
			if(state != 0)
				printf("%d --%c--> %d\n", i, j,state);
		}
	}
#endif
}


static inline int init_oracle_m(factor_m *pm)
{
	*(int*)pm = 0;
	return pm->cur_state;
}


static void print_ex(unsigned char *pch, unsigned char *pattern,int pattern_len, int offset, int color_nd)
{
#ifdef ILLUSTRATE
	int index = offset + color_nd;
	unsigned char bak_char = pch[index];
	pch[index] = 0;
	printf("%s", pch);
	pch[index] = bak_char;
	index = offset + pattern_len;
	bak_char = pch[index];
	pch[index] = 0;
	printcolor("%s", &pch[offset + color_nd]);
	pch[index] = bak_char;

	printf("%s\n", &pch[offset + pattern_len]);

	int i = 0;
	for(;i < offset; i++)
		printf(" ");
	printf("%s\n", pattern);
#endif
}


inline factor_m *new_oracle_m(unsigned char *pch)
{
	factor_m *pm = (factor_m*)calloc(1, sizeof(factor_m));
	int pattern_len = strlen(pch);
	pm->pattern_len = pattern_len;
	pm->p_state = calloc(pattern_len + 1, sizeof(state));
	pm->p_supply_state = calloc(pattern_len + 1, sizeof(unsigned char));
	pm->match_state = 1;
	int i;
	for(i = pattern_len - 1; i >= 0 ; i --)
	{
		oracle_add_letter(pm, (unsigned char)pch[i]);
	}

	print_oracle_state_m(pm);
	return pm;
}

inline void  free_oracle_m(factor_m *pm)
{
	free(pm);
}

int oracle_match(factor_m *pm, unsigned char *pch, int pch_len, unsigned char *pattern)
{
	int i = 0;
	int j;
	int cur_state;
	int pattern_len = pm->pattern_len;

	while(i <= pch_len - pattern_len)
	{
		//printf("i = %d\n", i);
		cur_state = init_oracle_m(pm);
		j = pattern_len;
		do{
			//printf("j = %d\n", j);
			cur_state = pm->p_state[cur_state].shift[pch[i + j - 1]];
			//printf("j cur_state = %d\n", cur_state);
			j --;
		}while(j > 0 && cur_state != 0);
		print_ex(pch, pattern, pattern_len, i, j);

		if(cur_state != 0)
			printcolor("match pattern pos %d\n", i);
		i = i + j + 1;
	}
	return 0;
}

